﻿using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Text;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
    struct XLUnicodeStringNoCch : IXLString
    {
        public override string ToString()
        {
            return _value + "(" + fHighByte + ")";
        }
        private string _value;
        private bool fHighByte;

        public int ByteLength
        {
            get
            {
                Contract.Assert(_value != null);
                if (fHighByte)
                    return _value.Length*2;
                return _value.Length;
            }
        }
        public int TotalByteLength
        {
            get
            {
                return ByteLength + 1;
            }
        }

        public void Read (BinaryReader reader, int count)
        {
#if DEBUG
            ReadWriteChecker.CheckStruct<XLUnicodeStringNoCch>(
                (ref XLUnicodeStringNoCch t, BinaryReader r) => t.Read(r, count),
                (ref XLUnicodeStringNoCch t, BinaryWriter w) => t.Write(w), reader, ref this);
#endif
            var b = reader.ReadByte();
            fHighByte = (b & 0x01) != 0;
            if (fHighByte)
            {
                _value = XlEncodings.TwoByteEncoding.GetString(reader.ReadBytes(count*2));
            }
            else
            {
                var bytes = reader.ReadBytes(count);
                _value = XlEncodings.OneByteEncoding.GetString(bytes);
            }
        }

        public static explicit operator string(XLUnicodeStringNoCch s)
        {
            return s._value;
        }
        public static explicit operator XLUnicodeStringNoCch(string s)
        {
            return new XLUnicodeStringNoCch(){_value = s};
        } 

        public void Write (BinaryWriter writer)
        {
            byte b = 0;
            if (fHighByte)
                b = 1;
            writer.Write(b);
            if (!fHighByte)
            {
#if DEBUG
                var test = XlEncodings.OneByteEncoding.GetBytes(_value);
#endif
                var bytes = XlEncodings.OneByteEncoding.GetBytes(_value);
                writer.Write(bytes);
                //Debug.WriteLine("Writing + _value " + string.Join("-", bytes));
            }
            else
            {
                var bytes = XlEncodings.TwoByteEncoding.GetBytes(_value);
                writer.Write(bytes);
                //Debug.WriteLine("Writing " + string.Join("-", bytes));

            }

        }

        public void ReadMulti(MultiBinaryReader readers, ushort count)
        {
            var b = readers.ReadByte();
            int remainingCount = count;
            fHighByte = (b & 0x01) != 0;
            bool highByte = fHighByte;
            StringBuilder sb = new StringBuilder();
            bool first = true;
            while (remainingCount > 0)
            {
                if (!first)
                {
                    b = readers.ReadByte();
                    highByte = (b & 0x01) != 0;
                    this.fHighByte = fHighByte | highByte;
                }
                if (highByte)
                {
                    byte[] bytes = readers.AttemptReadBytes(count*2);
                    var s = XlEncodings.TwoByteEncoding.GetString(bytes);
                    sb.Append(s);
                    remainingCount -= bytes.Length / 2;
                }
                else
                {
                    byte[] bytes = readers.AttemptReadBytes(count);
                    var s = XlEncodings.OneByteEncoding.GetString(bytes);
                    sb.Append(s);
                    remainingCount -= bytes.Length;
                }
                first = false;
            }
            _value = sb.ToString();
        }
    }
}